package agents;

import java.util.ArrayList;
import java.util.Random;

import environment.Casilla;
import environment.Tablero;
import gui.CasillasGUI;
import gui.TableroGUI;
import jade.core.Agent;
import jade.core.behaviours.TickerBehaviour;

public class Reactive extends Agent {
	private Tablero tablero;
	private int tickSpeed;
	private Casilla position;
	private int maxBat;
	private int battery;
	private int usedEnergy;
	private int storage;
	private Casilla[][] vision;
	private boolean end;
	
	/***/

	public void setup() {
		System.out.println("Initializing agent " + this.getName());
		Object[] argus = getArguments();
		this.tablero = (Tablero) argus[0];
		this.tickSpeed = (Integer) argus[1];
		this.maxBat = tablero.getSize();
		this.battery = tablero.getSize();
		this.usedEnergy = 0;
		this.storage = 0;
		this.position = tablero.requestStartPosition(this);
		this.end = false;
		
		
		addBehaviour(new TickerBehaviour(this, this.tickSpeed) {
			@Override
			protected void onTick() {
				vision = tablero.getVision(position);
				if (tablero.getActivePackages() == 0) {
					System.out.println("END");
					doDelete();
				} else if ( (position.hasLoader()) && (battery < maxBat) ) {
					System.out.println("LOAD");
					load(); 
				} else if (battery == 0) {
					System.out.println("DEAD");
					//load();
				} else if ( (storage != 0) &&  (battery <= (position.getGradiente() + 3) ) ) {
					//SI LLEVO UN PAQUETE Y SOLO ME DA LA ENERGIA PARA DEJARLO E IR A CARGAR
					System.out.println("BUSCANDO LOAD");
					if (portalCorrectoAdy()) {
						System.out.println("DEPO PORT");
						depositarPortal();
					} else {
						System.out.println("DEPO WE");
						depositarDondeSea();
					}
				} else if (battery <= position.getGradiente() + 2) {
					System.out.println("GRAD++");
					moverHaciaGradiente();
				} else if ( (storage != 0) && (portalCorrectoAdy() ) ) {
					System.out.println("DEPO PORT");
					depositarPortal();
				} else if ( (storage != 0) && (portalCorrectoVis() ) ) {
					System.out.println("MOVE PORT");
					moverHaciaPortal();
				} else if ( (storage == 0) && (paqueteAdy() ) ) {
					System.out.println("PICK PACK");
					cogerPaquete();
				} else if ( (storage == 0) && (paqueteVis() ) ) {
					System.out.println("MOVE PACK");
					moverHaciaPaquete();
				} else {
					System.out.println("NAVIGATE");
					navigate();
				}
			}
		});
	}
	
	/***/
	
	public void takeDown() {
		//TELL ENERGY USE
		System.out.println("Taking down agent " + this.getName());
		System.out.println(this.getName() + " used " + this.usedEnergy + " energy units");
		this.position.setAgentLoad(0);
		this.position.setContenido(0);
		this.position.updateGui();
		tablero.addUsedEnergy(this.usedEnergy);
	}

	
	/***/
	
	public static int randInt(int min, int max) {
	    Random rand = new Random();
	    int randomNum = rand.nextInt((max - min) + 1) + min;
	    return randomNum;
	}
	
	/***/
	
	//AGENT BASIC ACTIONS
	private void move(Casilla newpos) {
		System.out.println(this.getName() + " tries to move to " + newpos.coordsStr());
		if (newpos.getContenido() < 2) {
			//SI LA CASILLA ESTA VACIA O HAY UN CARGADOR, ME PUEDO MOVER
			if (storage == 0) {
				this.battery = this.battery - 1;
				this.usedEnergy = this.usedEnergy + 1;
			} else {
				this.battery = this.battery - 2;
				this.usedEnergy = this.usedEnergy + 2;
			}
			this.position.setAgentLoad(0);
			this.position.setContenido(this.position.getContenido() - 10);
			this.position.updateGui();
			newpos.setAgentLoad(this.storage);
			newpos.setContenido(newpos.getContenido() + 10);
			newpos.updateGui();
			this.position = newpos;
			System.out.println(this.getName() + " successfully moved to " + newpos.coordsStr());			
		} else {
			//Y SI NO, ME QUEDO EN MI SITIO
			System.out.println(this.getName() + " can't move to " + newpos.coordsStr() + " (already occupied position)");
		}
		
	}
	
	/***/
	
	private void niet() {
		System.out.println(this.getName() + " does nothing");	
	}
	
	/***/
	
	private void pick(Casilla from) {
		System.out.println(this.getName() + " tries to pick from " + from.coordsStr());
		if ( (this.storage == 0) && ( (from.getContenido() > 5) || (from.getContenido() < 10) ) ) {
			//SI HAY UN PAQUETE Y ESTOY VACIO, LO PUEDO COGER
			this.battery = this.battery - 1;
			this.usedEnergy = this.usedEnergy + 1;
			this.storage = from.getContenido();
			this.position.setAgentLoad(this.storage);
			this.position.updateGui();
			from.setContenido(0);
			from.updateGui();
			System.out.println(this.getName() + " picks from " + from.coordsStr());
		} else {
			System.out.println(this.getName() + " can't pick from " + from.coordsStr() + " (nothing to pick)");
		}
		
	}
	
	/***/
	
	private void depo(Casilla into) {
		System.out.println(this.getName() + " tries to deposit in " + into.coordsStr());
		if (into.getContenido() == 0) {
			//SI NO HAY NADA, LO PUEDO DEJAR
			this.battery = this.battery - 1;
			this.usedEnergy = this.usedEnergy + 1;
			into.setContenido(this.storage);
			into.updateGui();
			this.storage = 0;
			this.position.setAgentLoad(0);
			this.position.updateGui();
			System.out.println(this.getName() + " deposits in " + into.coordsStr());
		} else {
			if (into.getContenido() == this.storage - 4) {
				//SI LO QUE HAY ES UN PORTAL, LO PUEDO DEJAR
				this.battery = this.battery - 1;
				this.usedEnergy = this.usedEnergy + 1;
				this.storage = 0;
				this.position.setAgentLoad(0);
				this.position.updateGui();
				this.tablero.onePacketLess();
				System.out.println(this.getName() + " deposits in portal at " + into.coordsStr());
			} else {
				//SI HAY OTRA COSA, NO PUEDO HACER NADA
				System.out.println(this.getName() + " can't deposit in " + into.coordsStr() + " (already occupied position)");
			}
		}
	}
	
	/***/
	
	private void load() {
		System.out.println(this.getName() + " tries to load in " + this.position.coordsStr());
		if (this.position.hasLoader()) {
			//SI HAY UN CARGADOR
			if (this.battery < this.maxBat) {
				//Y LA BATERIA NO ESTA AL MAXIMO, CARGO
				this.battery = this.battery + 1;
				System.out.println(this.getName() + " loads");
				if (this.battery == this.maxBat) {
					System.out.println(this.getName() + " load complete");
				}
			} else {
				//BATERIA MAXIMA, NO CARGO
				System.out.println(this.getName() + " can't load (battery already full)");
			}
		} else {
			//NO HAY CARGADOR
			System.out.println(this.getName() + " can't load (no loader at current position)");
		}
	}
	
	/***/
	
	//METODOS COMPLEJOS AGENTE

	private boolean portalCorrectoAdy() {
		boolean hay = false;
		for (int i = 1; i < 4; i++) {
			for (int j = 1; j < 4; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido()) == (storage - 4))
						hay = true;
				}
			}
		}
		return hay;
	}
	
	/***/

	private void depositarPortal() {
		int x = 0, y = 0;
		for (int i = 1; i < 4; i++) {
			for (int j = 1; j < 4; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido()) == (storage - 4)) {
						x = i;
						y = j;
					}
				}
			}
		}
		depo(vision[x][y]);
		
	}
	
	/***/

	private void depositarDondeSea() {
		boolean hay = false;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if (vision[i][j].getContenido() == 0)
						hay = true;
				}
			}
		}
		if (hay) {
			int x, y;
			do {
				do {
					x = randInt(1,3);
					y = randInt(1,3);
				} while (  ( (x != 2) || (y != 2) ) && (vision[x][y] == null) );
			} while (vision[x][y].getContenido() != 0);
			depo(vision[x][y]);
		} else {
			niet();
		}
	}
	
	/***/

	private boolean portalCorrectoVis() {
		boolean hay = false;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido()) == (storage - 4) )
						hay = true;
				}
			}
		}
		return hay;
	}
	
	/***/

	private void moverHaciaGradiente() {
		int ref = position.getGradiente();
		int mej = 0;
		int x = 0, y = 0;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getGradiente() < position.getGradiente() ) && (vision[i][j].getContenido() < 2) ) {
						x = i;
						y = j;
						mej = ref - vision[i][j].getGradiente();
					}
				}
			}
		}
		//SI HAY GRADIENTE MEJOR, ME MUEVO, SINO, NO
		if (mej > 0) move(vision[x][y]);
		else niet();
		
	}
	
	/***/

	private void moverHaciaPortal() {
		int distX = 0, distY = 0;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido()) == (storage - 4) ) {
						distX = i-2;
						distY = j-2;
					}
				}
			}
		}
		if ( (distX == 0) && (distY == 0) ) return;
		else {
			if (distX == 0) {
				if (distY < 0) {
					if (vision[2][1].getContenido() == 0) move(vision[2][1]);
					else if (vision[1][1].getContenido() == 0) move(vision[1][1]);
					else if (vision[3][1].getContenido() == 0) move(vision[3][1]);
					else navigate();
				} else {
					if (vision[2][3].getContenido() == 0) move(vision[2][3]);
					else if (vision[1][3].getContenido() == 0) move(vision[1][3]);
					else if (vision[3][3].getContenido() == 0) move(vision[3][3]);
					else navigate();
				}			
			} else if (distY == 0) {
				if (distX < 0) {
					if (vision[1][2].getContenido() == 0) move(vision[1][2]);
					else if (vision[1][1].getContenido() == 0) move(vision[1][1]);
					else if (vision[1][3].getContenido() == 0) move(vision[1][3]);
					else navigate();
				} else {
					if (vision[3][2].getContenido() == 0) move(vision[3][2]);
					else if (vision[3][1].getContenido() == 0) move(vision[3][1]);
					else if (vision[3][3].getContenido() == 0) move(vision[3][3]);
					else navigate();
				}					
			} else if ( (distX < 0) && (distY < 0) ) {
				if (vision[1][1].getContenido() == 0) move(vision[1][1]);
				else if (vision[1][2].getContenido() == 0) move(vision[1][2]);
				else if (vision[2][1].getContenido() == 0) move(vision[2][1]);
				else navigate();
			} else if ( (distX < 0) && (distY > 0) ) {
				if (vision[1][3].getContenido() == 0) move(vision[1][3]);
				else if (vision[1][2].getContenido() == 0) move(vision[1][2]);
				else if (vision[2][3].getContenido() == 0) move(vision[2][3]);
				else navigate();
			} else if ( (distX > 0) && (distY < 0) ) {
				if (vision[3][1].getContenido() == 0) move(vision[3][1]);
				else if (vision[3][2].getContenido() == 0) move(vision[3][2]);
				else if (vision[2][1].getContenido() == 0) move(vision[3][1]);
				else navigate();
			} else if ( (distX > 0) && (distY > 0) ) {
				if (vision[3][3].getContenido() == 0) move(vision[3][3]);
				else if (vision[3][2].getContenido() == 0) move(vision[3][2]);
				else if (vision[2][3].getContenido() == 0) move(vision[2][3]);
				else navigate();
			}
			
		}
	}
	
	/***/

	private boolean paqueteAdy() {
		boolean hay = false;
		for (int i = 1; i < 4; i++) {
			for (int j = 1; j < 4; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido() > 5) && (vision[i][j].getContenido() < 10) )
						hay = true;
				}
			}
		}
		return hay;
	}
	
	/***/

	private void cogerPaquete() {
		int x = 0, y = 0;
		for (int i = 1; i < 4; i++) {
			for (int j = 1; j < 4; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido() > 5) && (vision[i][j].getContenido() < 10) ) {
						x = i;
						y = j;
					}
				}
			}
		}
		pick(vision[x][y]);
		
	}
	
	/***/

	private boolean paqueteVis() {
		boolean hay = false;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido() > 5) && (vision[i][j].getContenido() < 10) )
						hay = true;
				}
			}
		}
		return hay;
	}
	
	/***/

	private void moverHaciaPaquete() {
		int distX = 0, distY = 0;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if ( (vision[i][j].getContenido() > 5) && (vision[i][j].getContenido() < 10) ) {
						distX = i-2;
						distY = j-2;
					}
				}
			}
		}
		if ( (distX == 0) && (distY == 0) ) return;
		else {
			if (distX == 0) {
				if (distY < 0) {
					if (vision[2][1].getContenido() == 0) move(vision[2][1]);
					else if (vision[1][1].getContenido() == 0) move(vision[1][1]);
					else if (vision[3][1].getContenido() == 0) move(vision[3][1]);
					else navigate();
				} else {
					if (vision[2][3].getContenido() == 0) move(vision[2][3]);
					else if (vision[1][3].getContenido() == 0) move(vision[1][3]);
					else if (vision[3][3].getContenido() == 0) move(vision[3][3]);
					else navigate();
				}			
			} else if (distY == 0) {
				if (distX < 0) {
					if (vision[1][2].getContenido() == 0) move(vision[1][2]);
					else if (vision[1][1].getContenido() == 0) move(vision[1][1]);
					else if (vision[1][3].getContenido() == 0) move(vision[1][3]);
					else navigate();
				} else {
					if (vision[3][2].getContenido() == 0) move(vision[3][2]);
					else if (vision[3][1].getContenido() == 0) move(vision[3][1]);
					else if (vision[3][3].getContenido() == 0) move(vision[3][3]);
					else navigate();
				}					
			} else if ( (distX < 0) && (distY < 0) ) {
				if (vision[1][1].getContenido() == 0) move(vision[1][1]);
				else if (vision[1][2].getContenido() == 0) move(vision[1][2]);
				else if (vision[2][1].getContenido() == 0) move(vision[2][1]);
				else navigate();
			} else if ( (distX < 0) && (distY > 0) ) {
				if (vision[1][3].getContenido() == 0) move(vision[1][3]);
				else if (vision[1][2].getContenido() == 0) move(vision[1][2]);
				else if (vision[2][3].getContenido() == 0) move(vision[2][3]);
				else navigate();
			} else if ( (distX > 0) && (distY < 0) ) {
				if (vision[3][1].getContenido() == 0) move(vision[3][1]);
				else if (vision[3][2].getContenido() == 0) move(vision[3][2]);
				else if (vision[2][1].getContenido() == 0) move(vision[3][1]);
				else navigate();
			} else if ( (distX > 0) && (distY > 0) ) {
				if (vision[3][3].getContenido() == 0) move(vision[3][3]);
				else if (vision[3][2].getContenido() == 0) move(vision[3][2]);
				else if (vision[2][3].getContenido() == 0) move(vision[2][3]);
				else navigate();
			}
			
		}
	}
	
	/***/
	
	private void navigate() {
		boolean hay = false;
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 5; j++) {
				if (vision[i][j] != null) {
					if (vision[i][j].getContenido() == 0)
						hay = true;
				}
			}
		}
		if (hay) {
			int x, y;
			do {
				do {
					x = randInt(1,3);
					y = randInt(1,3);
				} while (  ( (x != 2) || (y != 2) ) && (vision[x][y] == null) );
			} while (vision[x][y].getContenido() != 0);
			move(vision[x][y]);
		} else {
			niet();
		}
	}
	
	/***/
	
	public int getStorage() {
		return storage;
	}


}
